/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#include "WorldInputHandler.hpp"

#include <OGRE/Ogre.h>

#include "CameraMan.hpp"
#include "EntityInterpolator.hpp" //TODO: get rid of this dep. later
#include "Game.hpp"
#include "Net.hpp"
#include "Presentation.hpp"
#include "PresentationDefs.hpp"
#include "WorldManager.hpp"
#include "WorldScene.hpp"
#include "Faction.hpp"
#include "Landscape.hpp"

#include "UglyDebug.hpp"

namespace spelprog2 {
namespace presentation {

bool WorldInputHandler::rayPick(Ogre::int32 mask, float x, float y, Ogre::RaySceneQueryResultEntry & out, bool movable)
{
    Ogre::Ray ray(game_.getCamera().getCameraToViewportRay(x, y));

    Ogre::RaySceneQuery * query;
    if (movable) {
        query = game_.getPresentation().getSceneManager().createRayQuery(ray, mask);
        query->setQueryTypeMask(Ogre::SceneManager::ENTITY_TYPE_MASK);
    }
    else {
        query = game_.getPresentation().getSceneManager().createRayQuery(ray, 0);
        query->setWorldFragmentType(static_cast<Ogre::SceneQuery::WorldFragmentType>(mask));
    }
    
    query->setSortByDistance(true, 1);
    query->execute();

    Ogre::RaySceneQueryResult & results = query->getLastResults();

    bool hadResult = false;
    if (!results.empty() && movable == (results[0].movable != 0) && results[0].distance > 0.0f) {
        out = results[0];
        hadResult = true;
    }

    game_.getPresentation().getSceneManager().destroyQuery(query);

    return hadResult;
}

WorldInputHandler::WorldInputHandler(Game & game, WorldScene & scene) :
    game_(game),
    scene_(scene)
{
}

void WorldInputHandler::injectMouseMove(float normalizedX, float normalizedY)
{
}

void WorldInputHandler::injectMouseDown(float normalizedX, float normalizedY, OIS::MouseButtonID button)
{
}

void WorldInputHandler::injectMouseUp(float normalizedX, float normalizedY, OIS::MouseButtonID button)
{
    if (button == OIS::MB_Left) {
        //if not shift key is held down {
            scene_.clearSelectedSquads();
        // }

        Ogre::RaySceneQueryResultEntry result;
        if (rayPick(ENTITY_QUERY_FLAG_UNIT, normalizedX, normalizedY, result, true)) {
            sim::Int playerId = Ogre::any_cast<sim::WideInt>(result.movable->getUserObjectBindings().getUserAny("player"));
            sim::Int squadId = Ogre::any_cast<sim::WideInt>(result.movable->getUserObjectBindings().getUserAny("squad"));

            scene_.addToSelectedSquads(SquadSelection(playerId, squadId));
        }
    }
    else if (button == OIS::MB_Right) {
        if (scene_.friendlySquadsSelected()) {
            Ogre::RaySceneQueryResultEntry result;
            if (rayPick(Ogre::SceneQuery::WFT_SINGLE_INTERSECTION, normalizedX, normalizedY, result, false)) {

                SquadSelections::ConstIteratorRange range = scene_.getSelectedSquads();
                for (SquadSelections::ConstIterator it = range.first; it != range.second; ++it) {
                    sim::Int2d pos(result.worldFragment->singleIntersection.x * float(sim::SCENE_TO_WORLD_SCALER),
                        result.worldFragment->singleIntersection.z * float(sim::SCENE_TO_WORLD_SCALER));

                    game_.getWorldManager().tryMoveSquad(it->getSquad(), pos);
                    
                    sim::Int2d squadPos = game_.getWorldManager().getWorld().getFaction(it->getPlayer()).getSquad(it->getSquad())->getPosition();
                    
                    LandscapeSpatials::PointList path;
                    game_.getWorldManager().getWorld().getLandscape().getSpatials().initPathFinder();
                    game_.getWorldManager().getWorld().getLandscape().getSpatials().findGroundUnitPath(squadPos, pos, path);
     
                    UglyDebug::getSingleton()->clear();
                    for(LandscapeSpatials::PointList::iterator i = path.begin(); i != path.end(); ++i)
                    {
                        UglyDebug::getSingleton()->addDebugMarker(float(i->x)/float(sim::SCENE_TO_WORLD_SCALER),
                            float(game_.getWorldManager().getWorld().getLandscape().getSpatials().getAltitude(*i))/float(sim::SCENE_TO_WORLD_SCALER),
                            float(i->y)/float(sim::SCENE_TO_WORLD_SCALER),
                            "Barrel.mesh");
                    }
                    
                    //TODO: check that selection has friendly squads (of same player) in case enemy squads should be selectable
                }
            }
        }
    }
}

void WorldInputHandler::lostMouseUp()
{
}

}; //presentation
}; //spelprog2
